#include "main.hpp"

static const long MAX_CPU_TIME_UPPERBOUND = 10;   //s
static const long MAX_CPU_TIME_LOWERBOUND = 1;    //s
static const long MAX_MEMORY_SIZE_UPPERBOUND = (200) * 8 * 1024 * 1024;   //(MB)->byte
static const long MAX_MEMORY_SIZE_LOWERBOUND = (20) * 8 * 1024 * 1024;    //(MB)->byte, note: I use AddressSanitizer, so don't use ulimit

static const long MAX_REAL_TIME = 20;     						//s (useless)

static const long MAX_STACK_SIZE = 16 * 1024 * 1024;  			//byte
static const long DEFAULT_MAX_STACK_SIZE = 16 * 1024 * 1024;  	//byte
static const long MAX_OUTPUT_SIZE = UNLIMITED;					//byte

/*
 * main:
 * para: int argc, char* argv[], argc must == 7, argv[1] is all testID(e.g. 20), argv[2] is dir(e.g. v7test/sort/cpp/), argv[3] is maxtime(s) (e.g. 1), argv[4] is maxmemory(MB) (e.g. 20)
 * argv[5] is the language: 0 means c++, 1 means javascript, other error
 * argv[6] is choose: only javascript need it: "0": one custom testcase(test), "1": many testcases(submit)
 * return code of struct_runOneCaseTest.code (GBL struct)
 */
int main(int argc, char* argv[]) {
	//init config
	struct structConfig mconfig;

    if (MAX_REAL_TIME > 0) mconfig.maxRealTime = MAX_REAL_TIME;
    else mconfig.maxRealTime = UNLIMITED;
	
    if (MAX_STACK_SIZE > 0) mconfig.maxStack = (long)MAX_STACK_SIZE;
    else mconfig.maxStack = DEFAULT_MAX_STACK_SIZE;
	
    if (MAX_OUTPUT_SIZE > 0) mconfig.maxOutputSize = (long)MAX_OUTPUT_SIZE;
    else mconfig.maxOutputSize = UNLIMITED;

	//mconfig.inputPathPos = setInputPathPos;          	//default: "/dev/stdin", don't use it
	mconfig.outputPathPos = RunOutputInfoPos;        	//default: "/dev/stdout"
	mconfig.errorPathPos = RunErrorInfoPos;          	//default: "/dev/stderr"
	mconfig.outPos = RunOutPos;
	
	//check para
	if (argc == 7) //argc must == 7
	{
		mconfig.testID = (std::string)argv[1];
		mconfig.dir = (std::string)argv[2];
		mconfig.type = (std::string)argv[5];
		mconfig.choose = (std::string)argv[6];
		
		if (mconfig.type != "0" && mconfig.type != "1"){
			return GBL_JSBP_OUTER_ERROR_PARA;
		}
		
		if (mconfig.choose != "0" && mconfig.choose != "1"){
			return GBL_JSBP_OUTER_ERROR_PARA;
		}
		
		try {
			long mct = std::stol((std::string)argv[3]);
			mct = min(mct, MAX_CPU_TIME_UPPERBOUND);
			mct = max(mct, MAX_CPU_TIME_LOWERBOUND);
			mconfig.maxCpuTime = mct;
			
			long mm = std::stol((std::string)argv[4]);
			mm = mm * 8 * 1024 * 1024;
			mm = min(mm, MAX_MEMORY_SIZE_UPPERBOUND);
			mm = max(mm, MAX_MEMORY_SIZE_LOWERBOUND);
			mconfig.maxMemory = mm;
		}
		catch (std::out_of_range &exc) {
			return GBL_JSBP_OUTER_ERROR_PARA;
		}
		catch (std::invalid_argument &exc) {
			return GBL_JSBP_OUTER_ERROR_PARA;
		}
		catch(...){
			return GBL_JSBP_OUTER_ERROR_PARA;
		}
	}
	else  //FUCK argc value
	{
		return GBL_JSBP_OUTER_ERROR_PARA;
	}

	int pid;
	pid = fork();
	if (pid == -1) {
		return GBL_JSBP_OUTER_ERROR_FORK;
	}
	else if (pid == 0) {
		ChildProcess(mconfig);  //with exit inside
	}
	else {
		return ParentProcess(mconfig, pid);
	}
	
	return GBL_JSBP_OUTER_ERROR_DEBUG; //dump
}
